package com.tanhua.server.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.commons.constant.Constants;
import com.tanhua.dubbo.api.db.QuestionApi;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.RecommendUserApi;
import com.tanhua.dubbo.api.mongo.UserLikeApi;
import com.tanhua.dubbo.api.mongo.UserLocationApi;
import com.tanhua.dubbo.api.mongo.VisitorApi;
import com.tanhua.model.db.Question;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.mongo.UserLocation;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.NearUserVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.RecommendUserQueryParam;
import com.tanhua.model.vo.TodayBest;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class TanhuaService {

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private UserLikeApi userLikeApi;

    @DubboReference
    private UserLocationApi userLocationApi;

    @DubboReference
    private VisitorApi visitorApi;

    @Value("${tanhua.default.recommend.users}")
    private String defaultRecommendUserIds;

    /**
     * 今日佳人
     * @return
     */
    public TodayBest todayBest() {
        //1. 通过登录用户id查询推荐的今日佳人recommendUser对象
        RecommendUser recommendUser = recommendUserApi.todayBest(UserHolder.getUserId());
        //1.1 如果没有佳人则给默认客服
        if(null == recommendUser){
            // 给客服
            recommendUser = new RecommendUser();
            recommendUser.setUserId(UserHolder.getUserId()%99 + 1); //1-99 客服
            recommendUser.setScore(82d);
        }
        //2. 取佳人id
        //3. userInfoApi通过佳人id查询佳人信息
        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());
        //4. 转成vo TodayBest
        TodayBest todayBest = TodayBest.init(userInfo, recommendUser);
        //5. 返回
        return todayBest;
    }

    /**
     * 首页好友推荐
     * @param queryParam
     * @return
     */
    public PageResult<TodayBest> recommendation(RecommendUserQueryParam queryParam) {
        //1. 通过登录用户id分页查询推荐的佳人列表
        PageResult pageResult = recommendUserApi.findPageByUserId(UserHolder.getUserId(),queryParam.getPage(), queryParam.getPagesize());
        List<RecommendUser> recommendUserList = pageResult.getItems();
        List<TodayBest> voList = new ArrayList<>();
        //1.1 如果没有推荐的佳人，则给客服，默认只给1页的数据
        if(CollectionUtil.isEmpty(recommendUserList) && queryParam.getPage() == 1){
            recommendUserList = getDefaultRecommendUser();
        }
        //判断是否有数据
        if(CollectionUtil.isNotEmpty(recommendUserList)) {
            //2. 获取所有佳人的id放到list集合
            //List<Long> userIds = recommendUserList.stream().map(RecommendUser::getUserId).collect(Collectors.toList());
            List<Long> userIds = new ArrayList<>();
            for (RecommendUser recommendUser : recommendUserList) {
                userIds.add(recommendUser.getUserId());
            }
            //3. 批量查询佳人信息(条件过滤)
            // key=用户id, value=用户信息, 佳人信息. 【注意】数量可能少于userIds。有些佳人因不满足条件而被过滤了.userInfoMap.size<=userIds(recommendUserList)
            Map<Long,UserInfo> userInfoMap = userInfoApi.findByBatchIds(userIds, getUserCondition(queryParam));
            //4. 转成vo,
            for (RecommendUser recommendUser : recommendUserList) {
                // 佳人id
                Long userId = recommendUser.getUserId();
                // 佳人信息, 【注意】userInfo有可能是空值，因为条件不满足被排除掉了
                UserInfo userInfo = userInfoMap.get(userId);
                if(null != userInfo) {
                    TodayBest vo = TodayBest.init(userInfo, recommendUser);
                    voList.add(vo);
                }
            }
        }
        // 设置到pageResult
        pageResult.setItems(voList);
        //5. 返回pageResult
        return pageResult;
    }

    /**
     * 构建查询用户详情时的过滤条件
     * @param queryParam
     * @return
     */
    private UserInfo getUserCondition(RecommendUserQueryParam queryParam) {
        UserInfo userInfoCondition = new UserInfo();
        userInfoCondition.setAge(queryParam.getAge()); // 使用小于
        userInfoCondition.setGender(queryParam.getGender());
        return userInfoCondition;
    }

    /**
     * 默认客服
     * @return
     */
    private List<RecommendUser> getDefaultRecommendUser() {
        List<RecommendUser> list = new ArrayList<>();
        for (long i = 1; i <=10 ; i++) {
            RecommendUser recommendUser = new RecommendUser();
            recommendUser.setUserId(i);
            recommendUser.setScore(Double.valueOf(63+i+UserHolder.getUserId()%10));
            //【注意】要添加到list
            list.add(recommendUser);
        }
        return list;
    }

    /**
     * 查看佳人信息
     * @param userId
     * @return
     */
    public TodayBest getUserInfo(Long userId) {
        //1. 查询佳人详情
        UserInfo userInfo = userInfoApi.findById(userId);
        //2. 查询登录用户与佳人缘分值
        RecommendUser recommendUser = recommendUserApi.findByUserId(UserHolder.getUserId(), userId);
        Double score = Double.valueOf(63+userId+UserHolder.getUserId()%10);
        if(null != recommendUser){
            score = recommendUser.getScore();
        }
        //3. 转vo
        TodayBest vo = new TodayBest();
        BeanUtils.copyProperties(userInfo,vo);
        vo.setTags(StringUtils.split(userInfo.getTags(), ","));
        // 放弃小数位
        vo.setFateValue(score.longValue());


        // 保存访客记录, 最好由MQ来实现  Topic模式：visitors.log  #.log  visitors.*
        Visitors visitors = new Visitors();
        visitors.setFrom("首页");
        visitors.setVisitorUserId(UserHolder.getUserId());
        visitors.setUserId(userId);
        visitors.setScore(score);
        visitorApi.save(visitors);

        //4. 返回
        return vo;
    }

    /**
     * 查看佳人的陌生人问题
     * @param userId
     * @return
     */
    public String strangerQuestions(Long userId) {
        //1. 通用用户id查询陌生人问题
        Question question = questionApi.findByUserId(userId);
        //2. 如果佳人没有设置陌生人问题，给默认值
        return null==question?"你喜欢我吗?":question.getTxt();
    }

    /**
     * 回复佳人的陌生人问题
     * @param paramMap
     */
    public void replyStrangerQuestions(Map<String, Object> paramMap) {

        //1. 查询登录用户的昵称
        UserInfo loginUser = userInfoApi.findById(UserHolder.getUserId());
        //2. 查询佳人的陌生人问题
        Long userId = ((Integer) paramMap.get("userId")).longValue();
        Question question = questionApi.findByUserId(userId);
        //3. 构建消息内容
        Map<String,Object> msgMap = new HashMap<String,Object>();
        msgMap.put("userId",UserHolder.getUserId());
        msgMap.put("huanXinId", UserHolder.getUser().getHxUser());
        msgMap.put("nickname",loginUser.getNickname());
        msgMap.put("strangerQuestion",null==question?"你喜欢我吗?":question.getTxt());
        msgMap.put("reply",paramMap.get("reply"));
        //4. 调用环信发送消息给佳人
        huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + userId, JSON.toJSONString(msgMap));
    }

    /**
     * 探花 列表
     * @return
     */
    public List<TodayBest> cards() {
        //1. 随机查询10个推荐用户，排除userLike表中的记录
        List<RecommendUser> list = recommendUserApi.findCards(UserHolder.getUserId(), 10);
        //2. 获取佳人ids, 查询佳人信息
        List<Long> userIds = new ArrayList<>();
        if(CollectionUtil.isEmpty(list)){
            //1.1 如果是刚注册用户，没有推荐，则给默认客服,从配置文件中来
            userIds = Arrays.stream(defaultRecommendUserIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        }else{
            // list .stream => 取每个元素来处理, (处理方式：调用每个元素的getUserId，返回userId值), 再收集(collect)起来，放到(toList())list
            userIds = list.stream().map(RecommendUser::getUserId).collect(Collectors.toList());
            for (RecommendUser recommendUser : list) {
                recommendUser.getUserId();
            }
        }
        List<UserInfo> userInfoList = userInfoApi.findByBatchIds(userIds);
        //3. 转成vo
        List<TodayBest> voList = userInfoList.stream().map(u -> TodayBest.init(u, null)).collect(Collectors.toList());
        //4. 返回
        return voList;
    }

    /**
     * 探花 - 右滑 喜欢
     * @param userId
     */
    public void love(Long userId) {
        //1. 调用UserLikeApi保存喜欢佳人
        Boolean flag = userLikeApi.love(UserHolder.getUserId(), userId);
        //2. 判断是否为好友， 如果为好友则在环信上注册为好友
        if(flag){
            huanXinTemplate.addContact(UserHolder.getUser().getHxUser(), Constants.HX_USER_PREFIX + userId);
        }
        //3. redis中标记登录用户喜欢了佳人
        String key = Constants.USER_LIKE_KEY + UserHolder.getUserId();
        stringRedisTemplate.opsForSet().add(key, userId.toString());
        //stringRedisTemplate.opsForSet().isMember(key, userId.toString())==true 代表登录用户喜欢了这个佳人
        //4. 从不喜欢列表中也移除
        key = Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId();
        stringRedisTemplate.opsForSet().remove(key, userId.toString());
    }

    /**
     * 探花 - 左滑 不喜欢
     * @param userId
     */
    public void unlove(Long userId) {
        //1. 调用api添加不喜欢
        userLikeApi.unLove(UserHolder.getUserId(), userId);
        //2. redis喜欢的标记要移除
        String key = Constants.USER_LIKE_KEY + UserHolder.getUserId();
        stringRedisTemplate.opsForSet().remove(key, userId.toString());
        //3. 从不喜欢列表中添加
        key = Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId();
        stringRedisTemplate.opsForSet().add(key, userId.toString());
    }

    /**
     * 搜附近
     * @param gender
     * @param distance
     * @return
     */
    public List<NearUserVo> searchNearBy(String gender, Long distance) {
        //1. 调用api搜附近
        List<Long> userIds = userLocationApi.searchNearBy(UserHolder.getUserId(), distance);
        //2. 获取ids
        List<NearUserVo> voList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(userIds)){
            //3. 查询佳人信息，过滤性别
            UserInfo userInfo = new UserInfo();
            userInfo.setGender(gender);
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByBatchIds(userIds, userInfo);
            //4. 转成vo
            voList = userInfoMap.values().stream().map(u -> NearUserVo.init(u)).collect(Collectors.toList());
        }
        //返回
        return voList;
    }
}
